package xlog

import (
	"fmt"
	"log/slog"
	"path/filepath"
	"runtime"
	"slices"
)

func caller(skip int) *slog.Source {
	var pc uintptr
	var pcs [1]uintptr
	runtime.Callers(3+skip, pcs[:])
	pc = pcs[0]
	fs := runtime.CallersFrames([]uintptr{pc})
	f, _ := fs.Next()
	return &slog.Source{
		Function: f.Function,
		File:     filepath.Base(f.File) + ":" + fmt.Sprintf("%d", f.Line),
	}
}

func addCaller(skip int, attrs ...slog.Attr) []slog.Attr {
	if slices.ContainsFunc(attrs, func(item slog.Attr) bool {
		return item.Key == "caller"
	}) {
		return attrs
	}
	source := caller(2)
	attrs = append(attrs, slog.String("caller", source.File))

	return attrs
}

func sortAttrs(attrs []slog.Attr) []slog.Attr {
	listMap := make(map[string]slog.Attr)
	for _, v := range attrs {
		listMap[v.Key] = v
	}
	listMap["caller"] = slog.Any("caller", caller(2))
	field := []string{"time", "level", "caller", "msg"}
	list := make([]slog.Attr, len(field))
	for idx, v := range field {
		list[idx] = listMap[v]
	}

	for _, v := range attrs {
		if slices.Contains([]string{"time", "level", "caller", "msg"}, v.Key) {
			continue
		}
		list = append(list, v)
	}

	return list
}
